/**
   @file serveur/theatre/echapper.hpp
   @brief Permet de découper un texte en mots, et de rassembler les
   mots en phrases. 
   @see decouper()
 */

#ifndef ECHAPPER_DEFINI

#define ECHAPPER_DEFINI

#include <QStringList>
#include <QVector>

/**
   @brief Découpe un QString en un QStringList.

   Le découpage se fait selon les espaces, les retours à la ligne, les
   tabulations. En cas de caractère échappé, le caractère
   correspondant est compris. Voici les différentes configurations :
   - '\\#' est compris comme un '#' dans un argument,
   - '\\n' est compris comme un retour à la ligne dans un argument,
   - '\\t' est compris comme une tabulation dans un argument,
   - '\\\\' est compris comme un antislash '\\' dans un argument,
   - '\\ ' est compris comme une espace ' ' dans un argument,
   - '\\012' est compris comme le code ASCII 12.

   Hors de ces configurations, par exemple '\\a', le caractère compris
   sera un point d'interrogation '?'

   Les commentaires sont tout ce qu'il y a entre un dièse hors d'une
   séquence guillemets et un retour à la ligne.

   @param contenu Le contenu à découper
   @return La liste des mots du fichier.
*/
QStringList decouper(const QString & contenu);

/**
   @brief Rassemble des mots en une phrase.
   
   À partir d'une suite de mots (obtenus par exemple avec decouper()),
   on les réorganise pour décrire un scénario de tarot.

   La grammaire est la suivante : selon le premier mot, on définit la
   structure du message : entier attendu ou pas. Ensuite, on
   sélectionne les mots répondant à cette structure en éliminant les
   mots qui ne correspondent pas.
   
   - identifier : on attend 2 arguments simples 
   ("identifier" et le nom). 
   - inviter : on attend 5 arguments simples 
   ("inviter" et les 4 noms).
   - priser : on attend 1 argument simple ("priser") et 1 entier (0 :
   passe, etc).
   - appeler : on attend 1 argument simple et 1 entier (la carte).
   - ecarter : on attend 1 a.s. et 3 entiers.
   - jouer : on attend 1 a.s. et 1 entier (la carte).
   - erreur_protocole : 1 a.s.
   - refuse : 1 a.s.
   - entree : 2 a.s.
   - sortie : 2 a.s.
   - noms : 6 a.s.
   - numero : 1 a.s., 1 entier.
   - distribution : 1 a.s., 15 entiers.
   - contrat : 1 a.s., 1 entier.
   - appel : 1 a.s.
   - contrat_final : 1 a.s., 3 entiers (le preneur, la prise, la carte
   appelée). 
   - chien : 1 a.s., 3 entiers.
   - atout : 1 a.s., jusqu'à 3 entiers. On s'arrête au premier
   non-entier trouvé.
   - jeu : 1 a.s.
   - carte : 1 a.s., 1 entier (la carte jouée).
   - pli : 1 a.s., 1 entier (le prochain joueur).
   - resultat : 1 a.s., 5 entiers.

   @param mots La liste des mots à rassembler.
   @param[out] ignored La liste des mots non pris en compte : soit des
   non-entiers à la place d'entiers, soit des têtes de phrase qui ne
   font pas partie de la liste ci-dessus.
   @return Un vecteur de phrases.
 */
QVector<QStringList> rassembler(const QStringList & mots,
				QStringList & ignored);

/**
   @brief Crée un scénario d'exemple.

   @param[out] out Là où il faut l'écrire.
   @return Le même flux, où on a écrit qqch.
 */
std::ostream & make_empty_scenario(std::ostream & out);


#ifdef TESTS_ECHAPPER
/**
   @brief Contenu par défaut à découper pour le test.
   @see TEST_CHAINE_DECOUPEE
   @see tester_decoupage()
 */
#define TEST_CHAINE_A_DECOUPER \
  "#Commentaire avec des \\#, des #, des \\, des \\n et des \\t : \t \nargument\\ 1 argumentA\\065\\\\ argumentB \n \t argument\\ C\\#dièse\n"
/**
   @brief Résultat attendu pour le test par défaut.
   @see TEST_CHAINE_A_DECOUPER
   @see tester_decoupage()
 */
#define TEST_CHAINE_DECOUPEE \
  QStringList() << "argument 1" << "argumentAA\\" << "argumentB" \
  <<"argument C#dièse"

/**
   @brief Teste la fonction decouper.

   Le test se fait de la manière suivante : une chaîne de caractères
   prédéfinie est découpée avec decouper(), puis le résultat est
   comparé à une liste prédéfinie. Si les listes ont le même nombre
   d'arguments et tous les éléments sont 2 à 2 identiques entre les
   listes, le résultat est vrai.
   
   @param[out] err Le message d'erreur, en cas de retour "false".
   @param test_a_decouper Le test à effectuer. Il existe un texte par
   défaut, voir TEST_CHAINE_A_DECOUPER et TEST_CHAINE_DECOUPEE.
   @param resultat_attendu Le résultat que l'on doit obtenir par
   decouper(). 
   @return vrai ssi le test a réussi.
 */
bool tester_decoupage(QString & err,
		      const QString & test_a_decouper 
		      = TEST_CHAINE_A_DECOUPER,
		      const QStringList & resultat_attendu 
		      = TEST_CHAINE_DECOUPEE);

#define TEST_MOTS_A_RASSEMBLER					\
  QStringList()							\
    <<"rien du tout"						\
    <<"identifier"<<"Jack l'éventreur"				\
    <<"interlude"						\
    <<"inviter"<<"a"<<"b"<<"c"<<"d"				\
    <<"Second interlude"					\
    <<"priser"<<"troll"<<"2"					\
    <<"appeler"<<"re-troll"<<"27"				\
    <<"entracte"						\
    <<"ecarter"<<"15"<<"16"<<"troll intersticiel"<<"17"		\
    <<"jouer"<<"troll joueur"<<"18"				\
    <<"pause"							\
    <<"erreur_protocole"					\
    <<"reuteuteu"						\
    <<"vacances"						\
    <<"refuse"							\
    <<"sortie"<<"Jack le Pas Bavard"				\
    <<"Bye bye !"						\
    <<"entree"<<"Un autre guignol"				\
    <<"noms"<<"a"<<"b"<<"c"<<"d"<<"e"				\
    <<"Congé payé"						\
    <<"Case chance"						\
    <<"Case départ"						\
    <<"numero"<<"encore un troll intersticiel"<<"4"		\
    <<"distribution"<<"0"<<"1"<<"bouh !"<<"bah !"<<"2"		\
    <<"3"<<"4"<<"5"<<"6"<<"7"<<"8"<<"Hem !"<<"9"<<"10"		\
    <<"11"<<"12"<<"13"<<"14"					\
    <<"Pause !"<<"c'est"<<"trop"<<"dur"<<"!"			\
    <<"contrat"<<"Jo l'incruste"<<"2"				\
    <<"appel"							\
    <<"contrat_final"<<"Jojo le fils de Jo"<<"0"<<"1"		\
    <<"2"							\
    <<"chien"<<"wouf !"<<"19"<<"45"<<"ouaf !"<<"23"		\
  <<"atout"<<"57"<<"58"						\
  <<"C'est tout pour les atouts !"				\
  <<"atout"							\
  <<"Et non !"							\
  <<"atout"<<"57"<<"58"<<"59"					\
  <<"jeu"							\
  <<"carte"<<"Mario carte"<<"56"				\
  <<"pli"<<"Origami"<<"1"					\
  <<"resultat"<<"positif"<<"-5"<<"10"<<"troll"<<"5"<<"-5"<<"-5"	\
  <<"Et c'est finiiiiiii"

#define TEST_PHRASES						\
  QVector<QStringList>()					\
  <<(QStringList()<<"identifier"<<"Jack l'éventreur")		\
    <<(QStringList()<<"inviter"<<"a"<<"b"<<"c"<<"d")		\
    <<(QStringList()<<"priser"<<"2")				\
    <<(QStringList()<<"appeler"<<"27")				\
    <<(QStringList()<<"ecarter"<<"15"<<"16"<<"17")		\
    <<(QStringList()<<"jouer"<<"18")				\
    <<(QStringList()<<"erreur_protocole")			\
    <<(QStringList()<<"refuse")					\
    <<(QStringList()<<"sortie"<<"Jack le Pas Bavard")		\
    <<(QStringList()<<"entree"<<"Un autre guignol")		\
    <<(QStringList()<<"noms"<<"a"<<"b"<<"c"<<"d"<<"e")		\
    <<(QStringList()<<"numero"<<"4")				\
    <<(QStringList()<<"distribution"<<"0"<<"1"<<"2"<<"3"<<"4"	\
       <<"5"<<"6"<<"7"<<"8"<<"9"<<"10"<<"11"<<"12"<<"13"<<"14")	\
    <<(QStringList()<<"contrat"<<"2")				\
    <<(QStringList()<<"appel")					\
  <<(QStringList()<<"contrat_final"<<"0"<<"1"<<"2")		\
  <<(QStringList()<<"chien"<<"19"<<"45"<<"23")			\
  <<(QStringList()<<"atout"<<"57"<<"58")			\
  <<(QStringList()<<"atout"<<"57"<<"58"<<"59")			\
  <<(QStringList()<<"jeu")					\
  <<(QStringList()<<"carte"<<"56")				\
  <<(QStringList()<<"pli"<<"1")					\
  <<(QStringList()<<"resultat"<<"-5"<<"10"<<"5"<<"-5"<<"-5")

#define TEST_MOTS_IGNORES					\
  QStringList()							\
    <<"rien du tout"<<"interlude"<<"Second interlude"<<"troll"	\
    <<"re-troll"<<"entracte"<<"troll intersticiel"		\
    <<"troll joueur"<<"pause"<<"reuteuteu"<<"vacances"		\
    <<"Bye bye !"<<"Congé payé"<<"Case chance"<<"Case départ"	\
    <<"encore un troll intersticiel"<<"bouh !"<<"bah !"		\
    <<"Hem !"<<"Pause !"<<"c'est"<<"trop"<<"dur"<<"!"		\
    <<"Jo l'incruste"<<"Jojo le fils de Jo"<<"wouf !"<<"ouaf !"	\
    <<"C'est tout pour les atouts !"<<"atout"<<"Et non !"	\
    <<"Mario carte"<<"Origami"<<"positif"<<"troll"		\
    <<"Et c'est finiiiiiii"

/**
   @brief Teste la fonction rassembler.

   @param[out] err Le message d'erreur, en cas de retour "false". 
   @param test_a_rassembler Les mots sans hiérarchie.
   @param resultat_attendu La liste des phrases que l'on attend.
   @param mots_ignores Les mots qui devraient être ignorés dans le
   processus.
   @return vrai ssi toutes les phrases correspondent au résultat
   attendu et tous les mots ignorés correspondent à ceux attendus.
 */
bool tester_rassemblement(QString & err,
			  const QStringList & test_a_rassembler =
			  TEST_MOTS_A_RASSEMBLER,
			  const QVector<QStringList> & resultat_attendu =
			  TEST_PHRASES,
			  const QStringList & mots_ignores =
			  TEST_MOTS_IGNORES);
#endif

#endif
